﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Web;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;

namespace ThrowModal.SP.WebParts.WPThrowModal
{
    [ToolboxItemAttribute(false)]
    public class WPThrowModal : WebPart
    {
        #region Constants
        private const string objectTagPrefix = "<object id='SilverlightObjectTag_WebPart_{0}' data='data:application/x-silverlight-2,' type='application/x-silverlight-2' style='display:block' height='{1}px' width='{2}px' class='ms-dlgDisable'>";
        private const string objectTagParam = "<param name='{0}' value='{1}'/>";
        private const string objectTagFallbackHTML = "<a href='http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0' style='text-decoration: none;'><img src='http://go.microsoft.com/fwlink/?LinkId=108181' alt='Get Microsoft Silverlight' style='border-style: none'/></a>";
        private const string objectInitParamUrl = "MS.SP.url={0}{1}";
        private const string objectTagSuffix = "</object>";
        #endregion

        protected override void CreateChildControls()
        {
            // set the web part size
            this.Height = 430;
            this.Width = 570;

            // create a string to construct the required JavaScript content
            StringBuilder modal = new StringBuilder();

            // open the script tag
            modal.Append("<script language='javascript' type='text/javascript'>");

            // declare an object to hold a pointer to the Silverlight control
            // this is required to enable a call to the Silverlight managed code
            // after the model results have been passed to the Callback function
            modal.Append("var SLcontrol = null;");

            // Get a pointer the the Silverlight control
            #region Silverlight Connection Javascript
            modal.Append("function pluginLoaded(sender, args)");
            modal.Append("{");
            modal.Append(" SLcontrol = sender.getHost();");
            modal.Append("}");
            #endregion

            // this will get called when the modal is closed
            #region CallBack Javascript
            modal.Append("function ThrowModalCallBack(dialogResult, returnValue)");
            modal.Append("{");
            modal.Append(" SLcontrol.Content.ThrowModalSL.HandleResult(returnValue); ");
            modal.Append(" if(dialogResult==1) ");
            modal.Append(" {");
            modal.Append("  var myNotifyId = SP.UI.Notify.addNotification('Callback result value: ' + returnValue, false); ");
            modal.Append(" }");
            modal.Append("}");
            #endregion

            // create the variations of JavaScript needed to throw each modal 
            #region Dialog Javascript
            modal.Append(CreateModalScript(true, true));
            modal.Append(CreateModalScript(true, false));
            modal.Append(CreateModalScript(false, true));
            modal.Append(CreateModalScript(false, false));
            #endregion

            // close the script tag
            modal.Append("</script>");

            // add the script to the page
            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ThrowModal", modal.ToString());

            // render the output tag for the Silverlight control
            Dictionary<string, string> p = new Dictionary<string, string>();
            // ensure the bind the pluginLoaded JavaScript function to the load event of our Silverlight control
            p.Add("onLoad", "pluginLoaded");
            Literal objectTag = new Literal();
            objectTag.Text = CreateObjectTag("/Style Library/Silverlight/ThrowModal.xap", SPContext.Current.Web, 570, 430, p, "Opps - something went wrong attempting to display the ThrowModal Silverlight control. Do you have the Silverlight browser installed?");

            // add the object tag to the control tree            
            this.Controls.Add(objectTag);
        }

        private static string CreateModalScript(bool useXY, bool autoSize)
        {
            string functionName = "ThrowModal";

            if (autoSize)
                functionName += "AutoSize";

            if (useXY)
                functionName += "XY";

            StringBuilder script = new StringBuilder();

            script.Append(string.Format("function {0}(urlParam, htmlParam, titleParam, callbackParam, argsParam, widthParam, heightParam, xParam, yParam, autosizeParam, allowmaximizeParam, showmaximizeParam, showcloseParam)", functionName));
            script.Append("{");
            script.Append(" var htmlElement = document.createElement('p');");
            script.Append(" var htmlNode = document.createTextNode(htmlParam);");
            script.Append(" htmlElement.appendChild(htmlNode);");
            script.Append(" var options = { ");
            script.Append("   html: htmlElement, ");
            script.Append("   url: urlParam, ");
            if (autoSize)
            {
                script.Append("   autoSize: autosizeParam, ");
            }
            else
            {
                script.Append("   width: widthParam, ");
                script.Append("   height: heightParam, ");
            }
            if (useXY)
            {
                script.Append("   x: xParam, ");
                script.Append("   y: yParam, ");
            }
            script.Append("   title: titleParam, ");
            script.Append("   allowMaximize: allowmaximizeParam, ");
            script.Append("   showMaximized: showmaximizeParam, ");
            script.Append("   showClose: showcloseParam, ");
            script.Append("   args: argsParam, ");
            script.Append("   dialogReturnValueCallback: ThrowModalCallBack");
            script.Append("};");
            script.Append(" window.focus(); ");
            script.Append("SP.UI.ModalDialog.showModalDialog(options); ");
            script.Append("}");

            return script.ToString();
        }

        /// <summary>
        /// Used to create an HTML object tag to encapsulate the required markup for rendering Silverlight controls (XAP files). 
        /// </summary>
        /// <param name="XapRelativeUrl">The relative url to the XAP file.</param>
        /// <param name="web">The SPWeb from the SPContent.Current</param>
        /// <param name="width">The width of the Silverlight control</param>
        /// <param name="height">The height of the Silverlight control</param>
        /// <param name="Params">The dictionary of parameters to be passed to the Silverlight control</param>
        /// <returns>A string containing the html object tag to be rendered</returns>
        private static string CreateObjectTag(string XapRelativeUrl, SPWeb web, int width, int height, Dictionary<string, string> Params)
        {
            return CreateObjectTag(XapRelativeUrl, web, width, height, Params, objectTagFallbackHTML);
        }

        /// <summary>
        /// Used to create an HTML object tag to encapsulate the required markup for rendering Silverlight controls (XAP files). 
        /// </summary>
        /// <param name="XapRelativeUrl">The relative url to the XAP file.</param>
        /// <param name="web">The SPWeb from the SPContent.Current</param>
        /// <param name="width">The width of the Silverlight control</param>
        /// <param name="height">The height of the Silverlight control</param>
        /// <param name="Params">The dictionary of parameters to be passed to the Silverlight control</param>
        /// <param name="FallbackHTML">The alternative HTML to be rendered is Silverlihght is not available in the client browser.</param>
        /// <returns>A string containing the html object tag to be rendered</returns>
        private static string CreateObjectTag(string XapRelativeUrl, SPWeb web, int width, int height, Dictionary<string, string> Params, string FallbackHTML)
        {
            if (Params == null)
                Params = new Dictionary<string, string>();

            if (web == null)
                return "Web object cannot be null for CreateObjectTag.";

            try
            {
                StringBuilder b = new StringBuilder();

                // create a unique id for the object tag
                string id = Guid.NewGuid().ToString().Replace("-", "_");

                // open object tag
                b.Append(String.Format(objectTagPrefix, id, height, width));

                // add Xap url param
                if (!Params.Keys.Contains("source")) Params.Add("source", XapRelativeUrl);

                // add default or required params
                if (!Params.Keys.Contains("background")) Params.Add("background", "white");
                if (!Params.Keys.Contains("windowsless")) Params.Add("windowsless", "true");
                if (!Params.Keys.Contains("onerror")) Params.Add("onerror", String.Format("_spOnSilverlightError_WebPart_{0}", id));

                // deal with the init params
                if (!Params.Keys.Contains("initParams"))
                {
                    // add the initParams
                    Params.Add("initParams", String.Format(objectInitParamUrl, SPEncode.UrlEncodeAsUrl(web.Url), ""));
                }
                else
                {
                    // append the initParams
                    Params["initParams"] = String.Format(objectInitParamUrl, SPEncode.UrlEncodeAsUrl(web.Url), ",") + Params["initParams"];
                }

                // append the params 
                foreach (string key in Params.Keys)
                {
                    b.Append(String.Format(objectTagParam, key, Params[key]));
                }

                // add Fallback HTML
                b.Append(objectTagFallbackHTML);

                // close obejct tag
                b.Append(objectTagSuffix);

                return b.ToString();
            }
            catch (Exception ex)
            {
                return String.Format("Error in CreateObjectTag - {0}", ex.Message);
            }
        }

    }


}
